`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2025/03/18 09:44:51
// Design Name: 
// Module Name: pwr_detect
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module pwm_detect(
    input           clk,
    input           rst_n,
    input           pwm_in,//2~5Khz
    
    output reg [13:0]   pwr_out
);
/*----------define----------*/
localparam      DAC_MIN = 14'd300;        
localparam      DAC_MAX = 14'd5461;     
localparam      CYCLE_MIN = 16'd20000;  //5Khz = 200000ns
localparam      CYCLE_MAX = 16'd50000;  //2khz = 500000ns

reg             pwm_r0,pwm_r1,pwm_r2;
reg             start;
reg     [15:0]  pwm_cycle;
reg     [15:0]  pwm_high;
reg     [15:0]  pwm_low;
reg     [15:0]  cycle_cnt;
reg     [15:0]  high_cnt;
reg     [15:0]  low_cnt;
reg             high_level;
reg     [13:0]  pwr_buf;

wire            pwm_pos;
wire            pwm_neg;
wire    [29:0]  dividend;
wire    [29:0]  divisor;
wire    [29:0]  quotient;
wire            finish;

assign pwm_pos  = pwm_r1 && pwm_r2 == 1'b0;
assign pwm_neg  = pwm_r1 == 1'b0 && pwm_r2;
assign dividend = pwm_high << 14;
assign divisor  = (pwm_cycle << 1) + pwm_cycle;

/*----------pwm cycle cnt----------*/
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin	
        pwm_r0 <= 1'b0;
        pwm_r1 <= 1'b0;
        pwm_r2 <= 1'b0;
    end
    else begin
        pwm_r0 <= pwm_in;
        pwm_r1 <= pwm_r0;
        pwm_r2 <= pwm_r1;
    end
end

always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
        cycle_cnt <= 16'd1;
    else if(pwm_pos) 
        cycle_cnt <= 16'd1;
	else if(cycle_cnt >= CYCLE_MAX)
        cycle_cnt <= CYCLE_MAX;	  
    else   
        cycle_cnt <= cycle_cnt + 1'b1;   
end

always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
        pwm_cycle <= 16'd0;
    else if(cycle_cnt >= CYCLE_MAX)
        pwm_cycle <= CYCLE_MAX; 
    else if(pwm_pos)begin
        if(cycle_cnt <= CYCLE_MIN)
            pwm_cycle <= CYCLE_MIN; 
        else   
            pwm_cycle <= cycle_cnt; 
    end
    else 
        pwm_cycle <= pwm_cycle;
end

/*----------pwm high level cnt----------*/
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
        high_level <= 1'b0;
    else if(pwm_neg)
        high_level <= 1'b0;
    else if(pwm_pos)
        high_level <= 1'b1;
    else 
        high_level <= high_level;
end

always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
        high_cnt <= 16'd1;
    else if(high_level == 1'b0) 
        high_cnt <= 16'd1;	  
    else if(high_cnt >= CYCLE_MAX)  
        high_cnt <= CYCLE_MAX;  
    else 
        high_cnt <= high_cnt + 1'd1;  
end

always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
        pwm_high <= 16'd0;
    else if(high_cnt >= CYCLE_MAX)
        pwm_high <= CYCLE_MAX; 
    else if(pwm_neg)
        pwm_high <= high_cnt; 
    else 
        pwm_high <= pwm_high;
end

/*----------pwm high level cnt----------*/
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
        low_cnt <= 16'd1;
    else if(high_level) 
        low_cnt <= 16'd1;
    else if(low_cnt >= CYCLE_MAX)
        low_cnt <= CYCLE_MAX; 
    else 
        low_cnt <= low_cnt + 1'b1;  
end

always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
        pwm_low <= 16'd0;
    else if(low_cnt >= CYCLE_MAX)
        pwm_low <= CYCLE_MAX; 
    else if(pwm_pos)
        pwm_low <= low_cnt; 
    else 
        pwm_low <= pwm_low;
end

/*----------pwr assign----------*/
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)
        pwr_out <= 14'd0;
    else if(pwm_low >= CYCLE_MAX)
        pwr_out <= DAC_MIN; 
    else if(pwm_high >= CYCLE_MAX)
        pwr_out <= DAC_MAX; 
    else if(finish)
        pwr_out <= quotient[13:0] > DAC_MIN ? quotient[13:0] : DAC_MIN;
end

/*----------pwm to pwr calculate----------*/
always @(posedge clk)begin
    if(pwm_pos)
        start <= 1'b1; 
    else 
        start <= 1'b0;
end

/*--------------------*/
divider#(
    .N          (8'd30)
)
divider(
	.clk		(clk),	
	.rst_n	    (rst_n),	
	.start	    (start),	
    .dividend   (dividend),	
	.divisor	(divisor),	
	
    .finish     (finish),
    .quotient   (quotient),
    .remainder  ()
);

endmodule
